package com.mm.learn.redis;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁
 */
@RestController
public class RedisLock {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${server.port}")
    private String serverPort;

    @Autowired
    private Redisson redisson;

    @GetMapping("/redisLock")
    public String redisLock() {
        String lockValue = UUID.randomUUID().toString();
        try {
            Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("redis-lock", lockValue, 20L, TimeUnit.SECONDS);
            if (!aBoolean) {
                return Thread.currentThread().getName() + ":抢锁失败";
            }
            String s = stringRedisTemplate.opsForValue().get("good:001");
            int goodCount = s == null ? 0 : Integer.parseInt(s);
            if (goodCount > 0) {
                int realCount = goodCount - 1;
                stringRedisTemplate.opsForValue().set("good:001", String.valueOf(realCount));
                System.out.println("成功买到商品，库存还剩下：" + realCount + "件" + "\t 服务提供端口" + serverPort);
                return "成功买到商品，库存还剩下：" + realCount + "件" + "\t 服务提供端口" + serverPort;
            } else {
                System.out.println("商品已售罄" + "\t 服务提供端口" + serverPort);
            }
            return "商品已售罄" + "\t 服务提供端口" + serverPort;
        } finally {
            //redis事务 保证原子性
          /*  while (true) {
                stringRedisTemplate.watch("redis-lock");
                if (stringRedisTemplate.opsForValue().get("redis-lock").equalsIgnoreCase(lockValue)) {
                    stringRedisTemplate.setEnableTransactionSupport(true);
                    stringRedisTemplate.multi();
                    stringRedisTemplate.delete("redis-lock");
                    List<Object> exec = stringRedisTemplate.exec();
                    if (exec == null) {
                        continue;
                    }
                }
                stringRedisTemplate.unwatch();
                break;
            }*/
            //lua脚本
            String script = "if redis.call('get',KEYS[1]) == ARGV[1]" +
                    "then" +
                    "return redis.call('del',KEYS[1])" +
                    "else" +
                    "return 0" +
                    "end";
            stringRedisTemplate.execute(new DefaultRedisScript<Integer>(script, Integer.class), Arrays.asList("redis-lock"), lockValue);

        }

    }

    @GetMapping("/redisson")
    public String redisson() throws InterruptedException {
        RLock lock = redisson.getLock("redis-lock");
        lock.lock();
        System.out.println("抢到锁了-------" + serverPort);
        try {
//            Thread.sleep(10000);
            String s = stringRedisTemplate.opsForValue().get("good:001");
            int goodCount = s == null ? 0 : Integer.parseInt(s);
            if (goodCount > 0) {
                int realCount = goodCount - 1;
                stringRedisTemplate.opsForValue().set("good:001", String.valueOf(realCount));
                System.out.println("成功买到商品，库存还剩下：" + realCount + "件" + "\t 服务提供端口" + serverPort);
                return "成功买到商品，库存还剩下：" + realCount + "件" + "\t 服务提供端口" + serverPort;
            } else {
                System.out.println("商品已售罄" + "\t 服务提供端口" + serverPort);
            }
            return "商品已售罄" + "\t 服务提供端口" + serverPort;
        } finally {
            if (lock.isLocked()) {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }

    }


}
